package com.lanou3g.demo;

import java.lang.reflect.*;

public class Main {
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        // 反射
        /*
        由什么组成一个类:
        修饰符
        类名
        属性
        构造方法
        方法

        由什么组成一个属性:
        修饰符
        数据类型
        变量名
        值

        什么组成构造方法:
        修饰符
        方法名
        参数

        什么组成方法:
        修饰符
        返回值
        方法名
        参数
         */

        /*
        存在任意一个类 P,
        P.class 代表获取到一个Class类的对象,
        该对象保存了P类的所有信息
         */
        Person p = new Person();
        Class<Person> clazz1 = Person.class;

        // 类的全名
        System.out.println(clazz1.getName());
        // 简称
        System.out.println(clazz1.getSimpleName());
        // 获取类加载器
//        clazz1.getClassLoader()



        // 有的时候, 有的是某个类的对象
        Class clazz2 = p.getClass();
        // 有的时候 即没有类也没有对象, 但是知道类名
        try {
            Class clazz3 = Class.forName("com.lanou3g.demo.Person");
            // 创建一个类的对象
            // 前提是存在默认的构造方法
            Object o = clazz3.newInstance();

            // 获取一个类的所有方法
            Method[] methods = clazz3.getDeclaredMethods();
            // 获取的是一个参数的eat方法
            Method eat = clazz3.getDeclaredMethod("eat", String.class);
            eat.setAccessible(true);

            Object result = eat.invoke(o, "大米饭");
            System.out.println(result);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        // 获取某个类的所有属性
        Field[] fields = clazz1.getDeclaredFields(); // 获取自己的所有属性
//        Field[] fields1 = clazz1.getFields(); // 获取自己及父类的所有public的属性
        Field name = clazz1.getDeclaredField("name");

        Field f = fields[0];
        int modifiers = f.getModifiers();
        System.out.println(Modifier.toString(modifiers));
        System.out.println(f.getType().getName());
        System.out.println(f.getName());
        // 获取某个属性的值, 前提是对象得存在.
        f.setAccessible(true);// 设置该属性为可访问的
        // 通过反射修改某个对象的某个属性的值
        f.set(p, "张小五");
//        System.out.println(p.name);

//        p.name = "王小二";
        // 通过反射读取某个属性的值
        Object o = f.get(p);// 相当于 p.name
        System.out.println(o);

        Constructor<?>[] constructors = clazz1.getConstructors();
        try {
            Constructor<Person> constructor = clazz1.getConstructor();
            Person p1 = constructor.newInstance();

            // 获取带参数的构造方法
            Constructor<Person> constructor1 = clazz1.getConstructor(String.class);
            Person p2 = constructor1.newInstance("燕小六");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }


//        Method eat = clazz1.getDeclaredMethod("eat", String.class, int.class);
        Method eat = clazz1.getDeclaredMethod("eat", String.class, Integer.TYPE);
        eat.invoke(p, "大米饭", 10);

    }
}
